#include <stdint.h>  
#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <getopt.h>  
#include <fcntl.h>  
#include <sys/ioctl.h>  
#include <linux/types.h>  
#include <linux/spi/spidev.h>  
#include "spi-test.h"
  
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))  

static int fd = -1; 
  
static void pabort(const char *s)  
{  
    perror(s);  
    abort();  
}  
  
static const char *device = "/dev/spidev0.0";  
static uint8_t mode;  
static uint8_t bits = 8;  
static uint32_t speed = 500000;  
static uint16_t delay;  
  
static void transfer(int fd)  
{  
    int ret;  
    uint8_t tx[] = {  
        0x00  
    };  
#if 1 
    /*uint8_t device_id[4] = {0};
    uint8_t regId = 0x1;
    write(fd, &regId, 1);
    read(fd, &device_id[0], 4); */

	uint8_t buf[15] = {0x12};
	read(fd, buf, 5);
    printf("read reg id 0x%x  device id 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 
	buf[0],buf[4],buf[3],buf[2],buf[1],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10]);

#else
    uint8_t rx[4] = {0};  
    struct spi_ioc_transfer tr = {  
        .tx_buf = (unsigned long)tx,  
        .rx_buf = (unsigned long)rx,  
        .len = ARRAY_SIZE(tx),  
        .delay_usecs = delay,  
        .speed_hz = speed,  
        .bits_per_word = bits,  
    };  
  
    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);  
    if (ret < 1)  
        pabort("can't send spi message");  
  
    for (ret = 0; ret < 4; ret++) {  
        if (!(ret % 6))  
            puts("");  
        printf("%.2X ", rx[ret]);  
    }  
    puts("");  
#endif
}  
  
static void print_usage(const char *prog)  
{  
    printf("Usage: %s [-DsbdlHOLC3]\n", prog);  
    puts("  -D --device   device to use (default /dev/spidev1.1)\n"  
         "  -s --speed    max speed (Hz)\n"  
         "  -d --delay    delay (usec)\n"  
         "  -b --bpw      bits per word \n"  
         "  -l --loop     loopback\n"  
         "  -H --cpha     clock phase\n"  
         "  -O --cpol     clock polarity\n"  
         "  -L --lsb      least significant bit first\n"  
         "  -C --cs-high  chip select active high\n"  
         "  -3 --3wire    SI/SO signals shared\n");  
    exit(1);  
}  
  
static void parse_opts(int argc, char *argv[])  
{  
    while (1) {  
        static const struct option lopts[] = {  
            { "device",  1, 0, 'D' },  
            { "speed",   1, 0, 's' },  
            { "delay",   1, 0, 'd' },  
            { "bpw",     1, 0, 'b' },  
            { "loop",    0, 0, 'l' },  
            { "cpha",    0, 0, 'H' },  
            { "cpol",    0, 0, 'O' },  
            { "lsb",     0, 0, 'L' },  
            { "cs-high", 0, 0, 'C' },  
            { "3wire",   0, 0, '3' },  
            { "no-cs",   0, 0, 'N' },  
            { "ready",   0, 0, 'R' },  
            { NULL, 0, 0, 0 },  
        };  
        int c;  
  
        c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);  
  
        if (c == -1)  
            break;  
  
        switch (c) {  
        case 'D':  
            device = optarg;  
            break;  
        case 's':  
           speed = atoi(optarg);  
            break;  
        case 'd':  
            delay = atoi(optarg);  
           break;  
        case 'b':  
           bits = atoi(optarg);  
            break;  
        case 'l':  
            mode |= SPI_LOOP;  
            break;  
        case 'H':  
            mode |= SPI_CPHA;  
            break;  
        case 'O':  
            mode |= SPI_CPOL;  
            break;  
        case 'L':  
            mode |= SPI_LSB_FIRST;  
            break;  
        case 'C':  
            mode |= SPI_CS_HIGH;  
            break;  
        case '3':  
            mode |= SPI_3WIRE;  
           break;  
        case 'N':  
            mode |= SPI_NO_CS;  
            break;  
        case 'R':  
            mode |= SPI_READY;  
            break;  
        default:  
            print_usage(argv[0]);  
            break;  
        }  
    }  
}  


int dwt_readfromdevice
(
    unsigned char  recordNumber,
    unsigned char  index,
    unsigned long   length,
    unsigned char   *buffer
)
{
    unsigned char header[3] = {0} ;                                       // buffer to compose header in
    unsigned short   cnt = 0;                                          // counter for length of header

    // Write message header selecting READ operation and addresses as appropriate (this is one to three bytes long)

	printf("dwt_readfromdevice recordNumber = 0x%x\n", recordNumber);
    if (index == 0)                                         // for index of 0, no sub-index is required
    {
        header[cnt++] = (unsigned char) recordNumber ;              // bit-7 zero is READ operation, bit-6 zero=NO sub-addressing, bits 5-0 is reg file id
    }
    else
    {
        header[cnt++] = (unsigned char)(0x40 | recordNumber) ;      // bit-7 zero is READ operation, bit-6 one=sub-address follows, bits 5-0 is reg file id

        if (index <= 127)                                   // for non-zero index < 127, just a single sub-index byte is required
        {
            header[cnt++] = (unsigned char) index ;                 // bit-7 zero means no extension, bits 6-0 is index.
        }
        else
        {
            header[cnt++] = 0x80 | (unsigned char)(index) ;           // bit-7 one means extended index, bits 6-0 is low seven bits of index.
            header[cnt++] =  (unsigned char) (index >> 7) ;           // 8-bit value = high eight bits of index.
        }
    }

    // do the read from the SPI

	printf("cnt = %d, 0x%x 0x%x 0x%x\n", cnt, header[0], header[1], header[2]);

    return readfrom_spi_serial(cnt, header, length, buffer);  // result is stored in the buffer

} // end dwt_readfromdevice()

int readfrom_spi_serial
(
    unsigned char       headerLength,
    unsigned char * headerBuffer,
    unsigned long       readlength,
    unsigned char       *readBuffer
)
{
#if 1
	unsigned char  buf[0x10];
	unsigned char  rx_buf[0x10] = {0};
#endif

	struct spi_ioc_transfer mesg[1];

#if 0
	unsigned char * buf;
	unsigned char * rx_buf;

	buf = headerBuffer;
	rx_buf = readBuffer;
#endif

	int retval = 0;
	int i = 0, index = 0;


	mesg[0].tx_buf = (__u32)buf;
	mesg[0].rx_buf = (__u32)rx_buf;
	mesg[0].len = headerLength + readlength;
	mesg[0].speed_hz = 500000;
	mesg[0].bits_per_word = 8;
	mesg[0].delay_usecs = 100;

	//*(unsigned char  *)(&buf[0]) = headerBuffer[0];
	//*(unsigned char  *)(&buf[1]) = headerBuffer[1];

	for (index = 0; index < headerLength; index++) {
		*(unsigned char  *)(&buf[index]) = headerBuffer[index];
	}

	#if 1
	for (i = 0; i < headerLength; i++) {
		printf("buf = 0x%x\n", *(unsigned char *)(&buf[i]));
		printf("headerBuffer = 0x%x\n", headerBuffer[i]);
	}
	#endif

#if 0
	if(headerLength == 1) {
			*(unsigned char  *)(&buf[index]) = headerBuffer[0];
			index++;
		} else {
			*(unsigned short  *)(&buf[index]) = headerBuffer[1] << 7| headerBuffer[0];
			index += 2;
		}
#endif

	/*for (i = 0; i < readlength; i++) {
		*(unsigned char *)(&buf[index]) = 0x00;
		index++;
	}*/

	retval = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);

	 if (retval < 1) 
		pabort("can't send spi message"); 

	printf("read buf:");
	for (i = 0; i < 0x10; i++) {
		printf(" 0x%x", *(unsigned char *)(&rx_buf[i]));
	}
	printf("\n");


	for (i = headerLength; i < readlength + headerLength; i++) {
		printf("result = 0x%x\n", *(unsigned char *)(&rx_buf[i]));
		readBuffer[i-headerLength] = *(unsigned char *)(&rx_buf[i]);
	}

#if 0
	for (i = 1; i < readlength+1; i++) {
		printf("result = 0x%x\n", *(unsigned char *)(&rx_buf[i]));
		readBuffer[i-1] = *(unsigned char *)(&rx_buf[i]);
	}
	
	printf("read reg id 0x%x 0x%x  device id  0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 
	mesg[0].rx_buf[0],mesg[0].rx_buf[1],mesg[0].rx_buf[2],mesg[0].rx_buf[3],mesg[0].rx_buf[4],
		mesg[0].rx_buf[5],mesg[0].rx_buf[6],mesg[0].rx_buf[7],mesg[0].rx_buf[8],mesg[0].rx_buf[9],mesg[0].rx_buf[10]);
#endif

	return 0;
}

int dwt_writetodevice
(
    unsigned int   recordNumber,
    unsigned int   index,
    unsigned int   length,
    unsigned char  *buffer
)
{
    unsigned char header[3] ;                                       // buffer to compose header in
    int   cnt = 0;                                          // counter for length of header

    // Write message header selecting WRITE operation and addresses as appropriate (this is one to three bytes long)

    if (index == 0)                                         // for index of 0, no sub-index is required
    {
        header[cnt++] = 0x80 | recordNumber ;               // bit-7 is WRITE operation, bit-6 zero=NO sub-addressing, bits 5-0 is reg file id
    }
    else
    {
        header[cnt++] = 0xC0 | recordNumber ;               // bit-7 is WRITE operation, bit-6 one=sub-address follows, bits 5-0 is reg file id

        if (index <= 127)                                   // for non-zero index < 127, just a single sub-index byte is required
        {
            header[cnt++] = (unsigned char)index ;                  // bit-7 zero means no extension, bits 6-0 is index.
        }
        else
        {
            header[cnt++] = 0x80 | (unsigned char)(index) ;           // bit-7 one means extended index, bits 6-0 is low seven bits of index.
            header[cnt++] =  (unsigned char) (index >> 7) ;           // 8-bit value = high eight bits of index.
        }
    }

	printf("write cnt = %d, 0x%x 0x%x 0x%x\n", cnt, header[0], header[1], header[2]);

    // write it to the SPI

    return writetospi_serial(cnt,header,length,buffer);

} // end dwt_writetodevice()

int writetospi_serial
(
    unsigned char       headerLength,
    unsigned char	*headerBuffer,
    unsigned int       bodylength,
    unsigned char	*bodyBuffer
)
{
#if 1
	unsigned char  buf[0x10] = {0};
	unsigned char  rx_buf[0x10] = {0};
#endif

	struct spi_ioc_transfer mesg[1];

	int retval = 0;
	int i = 0, index = 0;

	mesg[0].tx_buf = (__u32)buf;
	mesg[0].rx_buf = (__u32)rx_buf;
	mesg[0].len = headerLength + bodylength;
	mesg[0].speed_hz = 500000;
	mesg[0].bits_per_word = 8;
	mesg[0].delay_usecs = 100;

	printf("len : %d + %d = %d\n", headerLength, bodylength, headerLength + bodylength);

	for (index = 0; index < headerLength; index++) {
		*(unsigned char  *)(&buf[index]) = headerBuffer[index];
	}

	for (i = 0; i < bodylength; i++) {
		*(unsigned char  *)(&buf[index++]) = bodyBuffer[i];
	}

	printf("write buf:");
	for (i = 0; i < 0x10; i++) {
		printf(" 0x%x", *(unsigned char *)(&buf[i]));
	}
	printf("\n");

	
	retval = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);

	 if (retval < 1) 
		pabort("can't send spi message"); 



	#if 0

	printf("buf:");
	for (i = 0; i < 0x10; i++) {
		printf(" 0x%x", *(unsigned char *)(&rx_buf[i]));
	}
	printf("\n");

	
	for (i = 1; i < readlength+1; i++) {
		printf("result = 0x%x\n", *(unsigned char *)(&rx_buf[i]));
		readBuffer[i-1] = *(unsigned char *)(&rx_buf[i]);
	}
	#endif
	
}

void read_test()
{
	unsigned char       readBuffer[8] = {0};
	unsigned char i , readlength;

	readlength = 8;
	dwt_readfromdevice(0x08, 0x00, readlength, readBuffer);

	for (i = 0; i < readlength; i++) {
		printf("readBuffer = 0x%x\n", readBuffer[i]);
	}
}

void write_test()
{
	unsigned char  buf[4] = {0};

	unsigned char       readBuffer[8] = {0};
	unsigned char i , readlength;

    buf[1] = 0x7 & 0xff;
    buf[0] = 0xaa & 0xff;

    // Write the address
    dwt_writetodevice(0x2d,0x04,2,buf);

	// read
	readlength = 4;
	dwt_readfromdevice(0x2d, 0x04, readlength, readBuffer);

	for (i = 0; i < readlength; i++) {
		printf("readBuffer = 0x%x\n", readBuffer[i]);
	}


	buf[3] = 0x11 & 0xff;
    buf[2] = 0x22 & 0xff;
	buf[1] = 0x33 & 0xff;
    buf[0] = 0x44 & 0xff;

	dwt_writetodevice(0x2d,0x00,4,buf);

	// read
	readlength = 4;
	dwt_readfromdevice(0x2d, 0x00, readlength, readBuffer);

	for (i = 0; i < readlength; i++) {
		printf("readBuffer = 0x%x\n", readBuffer[i]);
	}
	
}

unsigned long dwt_read32bitoffsetreg(int regFileID,int regOffset)
{
    unsigned long  regval = -1 ;
    int     j ;
    unsigned char   buffer[4] = {0} ;

    int result = dwt_readfromdevice(regFileID,regOffset,4,buffer); // read 4 bytes (32-bits) register into buffer

    if(result == 0)
    {
        for (j = 3 ; j >= 0 ; j --)
        {
            regval = (regval << 8) + buffer[j] ;        // sum
			//printf("dwt_read32bitoffsetreg buffer = 0x%x\n", buffer[j]); 
        }
    }
    return regval ;

} 

unsigned long instancereaddeviceid(void)
{
    return dwt_readdevid() ;
}

unsigned long dwt_readdevid(void)
{
    return dwt_read32bitoffsetreg(DEV_ID_ID,0);
}

void id()
{
	unsigned long devID ;

	devID = instancereaddeviceid() ;
	printf("devid = 0x%lx\n", devID);
}


#if 1

void spi_init_test(int argc, char *argv[])
{
    int ret = 0;         
  
    parse_opts(argc, argv);  
 
    fd = open(device, O_RDWR);  
    if (fd < 0)  
        pabort("can't open device");  

    printf("open device sucucess %s\n", device);  
   /* 
    * spi mode 
     */  
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);  
    if (ret == -1)  
        pabort("can't set spi mode");  
  
    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);  
    if (ret == -1)  
        pabort("can't get spi mode");  
  
    /* 
     * bits per word 
     */  
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);  
    if (ret == -1)  
        pabort("can't set bits per word");  
  
    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);  
    if (ret == -1)  
        pabort("can't get bits per word");  
  
    /* 
     * max speed hz 
     */  
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);  
    if (ret == -1)  
        pabort("can't set max speed hz");  
  
    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);  
    if (ret == -1)  
        pabort("can't get max speed hz");  
 
    printf("spi mode: %d\n", mode);  
    printf("bits per word: %d\n", bits);  
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);  
}

int main(int argc, char *argv[])  
{  
	spi_init_test(argc, argv);
  
    read_test();
	write_test();
	id();
  
    close(fd);  
  
    return 0;  
}

#endif

#if 0
int main(int argc, char *argv[])  
{  
    int ret = 0;         
  
    parse_opts(argc, argv);  
 
    fd = open(device, O_RDWR);  
    if (fd < 0)  
        pabort("can't open device");  

    printf("open device sucucess %s\n", device);  
   /* 
    * spi mode 
     */  
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);  
    if (ret == -1)  
        pabort("can't set spi mode");  
  
    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);  
    if (ret == -1)  
        pabort("can't get spi mode");  
  
    /* 
     * bits per word 
     */  
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);  
    if (ret == -1)  
        pabort("can't set bits per word");  
  
    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);  
    if (ret == -1)  
        pabort("can't get bits per word");  
  
    /* 
     * max speed hz 
     */  
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);  
    if (ret == -1)  
        pabort("can't set max speed hz");  
  
    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);  
    if (ret == -1)  
        pabort("can't get max speed hz");  
 
    printf("spi mode: %d\n", mode);  
    printf("bits per word: %d\n", bits);  
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);  
  
    read_test();
	write_test();
	id();
  
    close(fd);  
  
    return 0;  
}
#endif
